//Bundle.scala
package mycore

import chisel3._
import chisel3.util._

abstract class MyBundle extends Bundle

//mycore IO
class InstFetch extends MyBundle{
	val en = Output(Bool())
	val addr = Output(UInt(64.W))
  val data = Input(UInt(32.W))
}

class DataLoad extends MyBundle{
	val en = Output(Bool())
	val addr = Output(UInt(64.W))
  val data = Input(UInt(64.W))
  val size = Output(UInt(3.W))
}

class DataStore extends MyBundle{
	val en = Output(Bool())
	val addr = Output(UInt(64.W))
  val data = Output(UInt(64.W))
  val mask = Output(UInt(8.W))
}

//pipeline buffer
class IFID extends MyBundle{
  val Valid = Output(Bool())
  val Inst = Output(UInt(32.W))
  val PC = Output(UInt(64.W))
}

class IDEX extends IFID {
  val isa = Output(new ISA)
  val src1 = Output(UInt(64.W))
  val src2 = Output(UInt(64.W))
  val imm = Output(new IMM)
  val wen = Output(Bool())
  val regdes = Output(UInt(5.W))
}

class EXMEM extends IDEX {
  val aluresult = Output(UInt(64.W))
  val branch = Output(Bool())
  val target = Output(UInt(64.W))
  val link = Output(UInt(64.W))
  val auipc = Output(UInt(64.W))
  val csrData = Output(UInt(64.W))
  val TimerInterrupt = Output(Bool())
  val EnvironmentCall = Output(Bool())
  val csr = Output(new CSR)
}

class MEMWB extends EXMEM {
  val loadData = Output(UInt(64.W))
  val clintValid = Output(Bool())
}

class WBDATA extends MyBundle {
	val wen = Output(Bool())
	val regdes = Output(UInt(5.W))
	val data = Output(UInt(64.W))
}

class NEXTPC extends MyBundle {
	val trap = Output(Bool())
	val mtvec = Output(UInt(64.W))
	val mret = Output(Bool())
	val mepc = Output(UInt(64.W))
	val branch = Output(Bool())
	val target = Output(UInt(64.W))
}

class MYAXI extends MyBundle {

	val AWVALID = Output(Bool())
	val AWREADY = Input(Bool())
	val AWSIZE = Output(UInt(3.W))
	val AWADDR = Output(UInt(64.W))

	val WVALID = Output(Bool())
	val WREADY = Input(Bool())
	val WSTRB = Output(UInt(8.W))
	val WDATA = Output(UInt(64.W))

	val BVALID = Input(Bool())
	val BREADY = Output(Bool())

	val ARVALID = Output(Bool())
	val ARREADY = Input(Bool())
	val ARSIZE = Output(UInt(3.W))
	val ARADDR = Output(UInt(64.W))

	val RVALID = Input(Bool())
	val RREADY = Output(Bool())
	val RDATA = Input(UInt(64.W))
	
}

class CSR extends MyBundle {
	val mcycle 	= UInt(64.W)
  val mstatus = UInt(64.W)
  val mtvec 	= UInt(64.W)
  val mcause 	= UInt(64.W)
  val mepc 		= UInt(64.W)
  val mie     = UInt(64.W)
  val mip     = UInt(64.W)
  val mscratch    = UInt(64.W)
  val medeleg     = UInt(64.W)
  val mhartid     = UInt(64.W)
}

class IMM extends MyBundle {

	val I = UInt(64.W)
	val B = UInt(64.W)
	val S = UInt(64.W)
	val U = UInt(64.W)
	val J = UInt(64.W)
	val Z = UInt(64.W)

}

class ISA extends MyBundle {

	//Arithmetic
	val ADD = Bool()
	val ADDI = Bool()
	val ADDW = Bool()
	val ADDIW = Bool()
	val SUB = Bool()
	val SUBW = Bool()
	val LUI = Bool()
	val AUIPC = Bool()
	//Logical
	val XOR = Bool()
	val XORI = Bool()
	val OR = Bool()
	val ORI = Bool()
	val AND = Bool()
	val ANDI = Bool()
	//Shifts
	val SLL = Bool()
	val SLLI = Bool()
	val SLLW = Bool()
	val SLLIW = Bool()
	val SRL = Bool()
	val SRLI = Bool()
	val SRLW = Bool()
	val SRLIW = Bool()
	val SRA = Bool()
	val SRAI = Bool()
	val SRAW = Bool()
	val SRAIW = Bool()
	//Compare
	val SLT = Bool()
	val SLTI = Bool()
	val SLTU = Bool()
	val SLTIU = Bool()
	//Branches
	val BEQ = Bool()
	val BNE = Bool()
	val BLT = Bool()
	val BGE = Bool()
	val BLTU = Bool()
	val BGEU = Bool()
	//Jump&Link
	val JAL = Bool()
	val JALR = Bool()
	//Sync
	val FENCE = Bool()
	val FENCE_I = Bool()
	//Environment
	val ECALL = Bool()
	val EBREAK = Bool()

	//Control Status Register(CSR)
	val CSRRW = Bool()
	val CSRRS = Bool()
	val CSRRC = Bool()
	val CSRRWI = Bool()
	val CSRRSI = Bool()
	val CSRRCI = Bool()

	//Loads
	val LD = Bool()
	val LW = Bool()
	val LH = Bool()
	val LB = Bool()
	val LWU = Bool()
	val LHU = Bool()
	val LBU = Bool()
	//Stores
	val SD = Bool()
	val SW = Bool()
	val SH = Bool()
	val SB = Bool()

	//Trap
	val MRET = Bool()
	val SRET = Bool()
	//Interrupt
	val WFI = Bool()
	//MMU
	val SFENCE_VMA = Bool()

	//Default: ILL means illegal
	val ILL = Bool()

}

//from NutShell
object SignExt {
  def apply(a: UInt, len: Int) = {
    val aLen = a.getWidth
    val signBit = a(aLen-1)
    if (aLen >= len) a(len-1,0) else Cat(Fill(len - aLen, signBit), a)
  }
}

object ZeroExt {
  def apply(a: UInt, len: Int) = {
    val aLen = a.getWidth
    if (aLen >= len) a(len-1,0) else Cat(0.U((len - aLen).W), a)
  }
}
